package com.hxd.mall.utils.local

import android.os.Looper
import android.util.Log
import android.widget.Toast
import com.hxd.mall.constant.HxdConstants.Sd_Card_Document_Folder
import com.hxd.mall.constant.HxdGlobalInfo
import com.hxd.mall.utils.open.FileUtil
import com.hxd.mall.utils.open.TimeUtil
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.PrintStream


/**
 * UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告.
 * 需要在Application中注册，为了要在程序启动器就监控整个程序。
 */
class CrashHandlerUtil
/**
 * 保证只有一个CrashHandler实例
 */
private constructor() : Thread.UncaughtExceptionHandler {

    private object MakeInstance {
        var instance = CrashHandlerUtil()
        internal var mDefaultHandler: Thread.UncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler()
    }

    /**
     * 初始化
     */
    fun init() {
        //获取系统默认的UncaughtException处理器
        // mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        //设置该CrashHandler为程序的默认处理器
        Thread.setDefaultUncaughtExceptionHandler(instance)
    }

    /**
     * 当UncaughtException发生时会转入该函数来处理
     */
    override fun uncaughtException(thread: Thread, ex: Throwable) {
        if (!handleException(ex)) {
            //如果用户没有处理则让系统默认的异常处理器来处理
            handlerInstance.uncaughtException(thread, ex)
        } else {
            try {
                Thread.sleep(1000)
            } catch (e: InterruptedException) {
                Log.e(TAG, "error : ", e)
            }

            //退出程序
            StackManageUtil.closeAll()
            android.os.Process.killProcess(android.os.Process.myPid())
            System.exit(0)
            System.gc()
        }
    }

    /**
     * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
     *
     * @param ex
     * @return true:如果处理了该异常信息;否则返回false.
     */
    private fun handleException(ex: Throwable?): Boolean {
        if (ex == null) {
            return false
        }

        //保存日志文件
        try {
            val error = exceptionSimple(ex)
            // log print
            FileUtil.writeAppendToFile(Sd_Card_Document_Folder + "hxd_crash.txt",
                    TimeUtil.getNowDataStr() + " " + error)
        } catch (e: IOException) {
            e.printStackTrace()
        }

        object : Thread() {
            override fun run() {
                Looper.prepare()
                Toast.makeText(HxdGlobalInfo.instance, "很抱歉,程序出现异常,即将退出.", Toast.LENGTH_LONG).show()
                Looper.loop()
            }
        }.start()
        return true
    }

    companion object {
        private val TAG = "CrashHandlerUtil"

        val instance: CrashHandlerUtil
            get() = MakeInstance.instance

        private val handlerInstance: Thread.UncaughtExceptionHandler
            get() = MakeInstance.mDefaultHandler

        /**
         * 将异常信息转化成字符串(优化字符串信息)
         * @throws IOException
         */
        @Throws(IOException::class)
        fun exceptionSimple(t: Throwable?): String? {
            if (t == null) return null

            val exceptionString = exception(t)
                    ?: return null
            val exceptions = exceptionString.split("\n\t".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
            val sb = StringBuffer(t.toString() + "\n")

            if (exceptions == null || exceptions.size == 0) {
                return sb.toString()
            }

            for (i in exceptions.indices) {
                val temp = exceptions[i] ?: return sb.toString()
                if (temp.contains("Exception:") || temp.contains("com.hexindai.pocketloan") || temp.contains("Caused by")) {
                    sb.append(exceptions[i] + "\n")
                }
            }

            return sb.toString()
        }

        /**
         * 将异常信息转化成字符串
         *
         * @param t
         * @return
         * @throws IOException
         */
        @Throws(IOException::class)
        fun exception(t: Throwable?): String? {
            if (t == null) return null
            val output = ByteArrayOutputStream()
            try {
                t.printStackTrace(PrintStream(output))
            } finally {
                output.close()
            }

            return output.toString()
        }
    }
}
